package com.siruier.boss.ui.helper

import android.content.Context
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import com.alipay.sdk.app.PayTask
import com.siruier.boss.BuildConfig
import com.siruier.boss.R
import com.siruier.boss.api.LOGIN_API_SERVICE
import com.siruier.boss.api.MALL_API_SERVICE
import com.siruier.boss.api.core.FirmException
import com.siruier.boss.api.core.launchUI
import com.siruier.boss.api.core.toData
import com.siruier.boss.bean.PayChannel
import com.siruier.boss.bean.PayModel
import com.siruier.boss.bean.PayOrder
import com.siruier.boss.bean.WeChatPayParamsBean
import com.siruier.boss.common.*
import com.siruier.boss.ui.activity.commom.openUrl
import com.siruier.boss.ui.activity.user.RealNameAuthActivity
import com.siruier.boss.ui.activity.user.SettingMoneyPasswrodActivity
import com.siruier.boss.ui.base.BaseActivity
import com.siruier.boss.ui.cache.UserCache
import com.siruier.boss.ui.dialog.InputDialog
import com.siruier.boss.ui.dialog.PayAwaitDialog
import com.siruier.boss.ui.dialog.PayChannelDialog
import com.siruier.boss.ui.dialog.showAlertDialog
import com.siruier.boss.ui.utils.Logger
import com.siruier.boss.ui.utils.SafeDialogHandle
import com.siruier.boss.wxapi.WXEntryActivity
import com.siruier.boss.wxapi.WXPayEntryActivity
import com.tencent.mm.opensdk.constants.ConstantsAPI
import com.tencent.mm.opensdk.modelbiz.WXLaunchMiniProgram
import com.tencent.mm.opensdk.modelpay.PayReq
import com.tencent.mm.opensdk.openapi.IWXAPI
import com.tencent.mm.opensdk.openapi.WXAPIFactory
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.withContext
import java.math.BigDecimal
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException


const val PAY_LLWX = "llwx"
const val PAY_LLALI = "llali"
const val PAY_WX = "wx"
const val PAY_ALI = "ali"
const val PAY_YE = "ye"
const val PAY_YJ = "yj"

private const val MESSAGE_UN_PAY_PASSWORD = "取消设置支付密码"
private const val MESSAGE_UN_AUTH = "取消实名认证"

suspend fun BaseActivity<*>.checkPayPasswordAndRealNameAuth() {
    checkPayPassword()
    checkRealNameAuth()
}

suspend fun BaseActivity<*>.checkPayPassword() = suspendCancellableCoroutine<Boolean> { coroutine ->
    if (UserCache.getUserInfoBean().setPayPassword != 1) {
        showAlertDialog {
            mCancelable = false
            message(message = "请先设置资金密码")
            negativeButton {
                coroutine.resumeWithException(FirmException(MESSAGE_UN_PAY_PASSWORD))
            }
            closeCallback = { coroutine.resumeWithException(FirmException(MESSAGE_UN_PAY_PASSWORD)) }
            positiveButton(R.string.button_go_setting) {
                launchStartActivityForResult(SettingMoneyPasswrodActivity::class.java, isNeedResultOk = false) {
                    if (UserCache.getUserInfoBean().setPayPassword == 1) {
                        coroutine.resume(true)
                    } else {
                        coroutine.resumeWithException(FirmException(MESSAGE_UN_PAY_PASSWORD))
                    }
                }
            }
        }
    } else {
        coroutine.resume(true)
    }
}

suspend fun BaseActivity<*>.checkRealNameAuth() = suspendCancellableCoroutine { coroutine ->
    if (UserCache.getUserInfoBean().authStatus != 1) {
        showAlertDialog {
            mCancelable = false
            message(message = "请先实名认证")
            negativeButton {
                coroutine.resumeWithException(FirmException(MESSAGE_UN_AUTH))
            }
            closeCallback = { coroutine.resumeWithException(FirmException(MESSAGE_UN_AUTH)) }
            positiveButton(R.string.button_go_auth) {
                launchStartActivityForResult(RealNameAuthActivity::class.java, isNeedResultOk = false) {
                    if (UserCache.getUserInfoBean().authStatus == 1) {
                        coroutine.resume(true)
                    } else {
                        coroutine.resumeWithException(FirmException(MESSAGE_UN_AUTH))
                    }
                }
            }
        }
    } else {
        coroutine.resume(true)
    }
}

suspend fun BaseActivity<*>.inputPayPassword() = suspendCancellableCoroutine { coroutine ->
    InputDialog.showMallPayPassword(this, {
        coroutine.resume(null)
    }) {
        coroutine.resume(it)
    }
}

suspend fun BaseActivity<*>.payChannel(orderPrice: BigDecimal, discount: BigDecimal, showDk: Boolean = true): PayModel {
    UserCache.saveBalanceTotal(LOGIN_API_SERVICE.balanceTotal().toData())
    val payChannels = MALL_API_SERVICE.payChannel().toData() ?: throw FirmException("暂无也可用支付通道")
    if (payChannels.isEmpty()) {
        throw FirmException("暂无也可用支付通道")
    }
    return payChannelSelect(payChannels, orderPrice, discount, showDk)
}

suspend fun BaseActivity<*>.payChannelSelect(
    payChannels: MutableList<PayChannel>,
    orderPrice: BigDecimal,
    discount: BigDecimal,
    showDk: Boolean,
) = suspendCancellableCoroutine { coroutine ->
    val mPayChannelDialog = PayChannelDialog(this, showDk, orderPrice, discount, payChannels, {
        coroutine.resumeWithException(FirmException("支付取消"))
    }, coroutine::resume)
    coroutine.invokeOnCancellation {
        mPayChannelDialog.dismiss()
    }
    mPayChannelDialog.show()
}

suspend fun BaseActivity<*>.pay(payModel: PayModel): Boolean {
    val payOrder: PayOrder = if (PAY_LLWX == payModel.payWay) {
        payPayLlwx(payModel)
    } else {
        // 获取支付信息
        MALL_API_SERVICE.orderPay(
            payModel.orderPrice.formatPrice(), payModel.balance.formatPrice(), payModel.integral.formatPrice(),
            payModel.orderSn, payModel.payWay, payModel.phone, payModel.orderType
        ).toData() ?: return false
    }
    if (1 == payOrder.isPayInvoke) {
        val pay = when (payModel.payWay) {
            PAY_WX -> payWxReq(this, payOrder.weChatPayParams ?: throw FirmException("微信支付参数异常"))
            PAY_ALI -> payAliReq(payOrder.prepayContent ?: throw FirmException("支付宝支付参数异常"))
            PAY_LLALI -> payPayLlali(payModel, payOrder.prepayContent ?: throw FirmException("支付宝支付参数异常"))
            else -> throw FirmException("暂未支持的支付方式")
        }
        if (!pay) {
            return false
        }
    }
    // 等1秒再查询结果，给后台留点回调时间
    delay(1000)
    var payStatus: Int? = null
    // 循环查询3次
    for (index in 1..3) {
        payStatus = MALL_API_SERVICE.payQuery(payOrder.orderNo).toData()?.payStatus
        if (payStatus != 1) {
            delay(3000)
        } else {
            break
        }
    }
    // 查询到状态还是不正常
    if (payStatus != 1) {
        throw FirmException("支付结果查询失败")
    }
    localSendBroadcastSync(ACTION_USER_INFO_CHANGE)
    return true
}

private suspend fun BaseActivity<*>.payAliReq(aliPayData: String): Boolean {
    val result = withContext(Dispatchers.IO) {
        val alipay = PayTask(this@payAliReq)
        alipay.payV2(aliPayData, true)
    }
    if ("9000" != result["resultStatus"]) {
        throw FirmException(result["memo"])
    }
    return true
}

private suspend fun payWxReq(
    context: Context,
    wxPayData: WeChatPayParamsBean,
) = suspendCancellableCoroutine { coroutine ->
    coroutine.invokeOnCancellation {
        Logger.e("支付协程取消")
        WXPayEntryActivity.wxPayCallback = null
    }
    val wxApi: IWXAPI = WXAPIFactory.createWXAPI(context, null)
    wxApi.registerApp(wxPayData.appId)
    val request = PayReq()
    request.appId = wxPayData.appId
    request.partnerId = wxPayData.partnerId
    request.prepayId = wxPayData.prepayId
    request.packageValue = wxPayData.packageValue
    request.nonceStr = wxPayData.nonceStr
    request.timeStamp = wxPayData.timeStamp
    request.sign = wxPayData.sign
    wxApi.sendReq(request)
    WXPayEntryActivity.wxPayCallback = { resp ->
        Logger.e("支付结果 resp.type==>${resp.type}")
        Logger.e("支付结果 resp.errCode==>${resp.errCode}")
        if (resp.type == ConstantsAPI.COMMAND_PAY_BY_WX)
            when (resp.errCode) {
                0 -> coroutine.resume(true)
                -1 -> coroutine.resumeWithException(FirmException("微信支付异常，请联系客服"))
                -2 -> coroutine.resumeWithException(FirmException("取消微信支付"))
            }
    }
}

private suspend fun BaseActivity<*>.payPayLlwx(payModel: PayModel): PayOrder {
    val needQuery = suspendCancellableCoroutine { coroutine ->
        val appId = MINI_PROGRAM_APP_ID
        val api = WXAPIFactory.createWXAPI(applicationContext, appId)
        val req = WXLaunchMiniProgram.Req()
        req.userName = MINI_PROGRAM_USER_NAME
        req.path =
            "pages/pay/pay?orderNo=${payModel.orderSn}&amount=${payModel.orderPrice ?: 0}" +
                    "&token=${UserCache.getToken()}&balance=${payModel.balance ?: 0}" +
                    "&integral=${payModel.integral ?: 0}&orderType=${payModel.orderType}" +
                    "&phone=${payModel.phone ?: ""}"
        req.miniprogramType = if (BuildConfig.DEBUG) {
            WXLaunchMiniProgram.Req.MINIPROGRAM_TYPE_PREVIEW
        } else {
            WXLaunchMiniProgram.Req.MINIPTOGRAM_TYPE_RELEASE
        }

        Logger.e("req.path==>${req.path}")
        api.sendReq(req)
        val dialog = PayAwaitDialog(this)
        dialog.setOnDismissListener {
            if (coroutine.isActive) {
                coroutine.resume(true)
            }
        }
        dialog.show()
        WXEntryActivity.wxMiniProgramPayCallback = { resp ->
            if (resp.type == ConstantsAPI.COMMAND_LAUNCH_WX_MINIPROGRAM) {
                val launchMiniProResp = resp as WXLaunchMiniProgram.Resp
                val extraData = launchMiniProResp.extMsg
                Logger.e("extraData==>${extraData}")
                if (coroutine.isActive) {
                    if ("success" == extraData) {
                        coroutine.resume(true)
                    } else {
                        coroutine.resumeWithException(FirmException("支付失败"))
                    }
                    SafeDialogHandle.safeDismissDialog(dialog)
                }
            }
        }
        coroutine.invokeOnCancellation {
            SafeDialogHandle.safeDismissDialog(dialog)
            WXEntryActivity.wxMiniProgramPayCallback = null
        }

        // 本来支付完成需要取消注册的，但是这里实在不好取消等爷页面销毁删除吧
        lifecycle.addObserver(object : DefaultLifecycleObserver {
            override fun onResume(owner: LifecycleOwner) {
                owner.launchUI({
                    Logger.e("返回页面支付成功==>")
                    if (coroutine.isActive) {
                        if (checkPay(payModel.orderSn)) {
                            WXEntryActivity.wxMiniProgramPayCallback = null
                            SafeDialogHandle.safeDismissDialog(dialog)
                            coroutine.resume(false)
                        }
                    }
                })
            }
        })
    }
    if (needQuery && !checkPay(payModel.orderSn)) {
        throw FirmException("支付失败")
    }
    return PayOrder(orderNo = payModel.orderSn!!, isPayInvoke = 0)
}

private suspend fun BaseActivity<*>.payPayLlali(payModel: PayModel, prepayContent: String) = suspendCancellableCoroutine { coroutine ->
    openUrl(prepayContent)
    val dialog = PayAwaitDialog(this)
    dialog.setOnDismissListener {
        if (coroutine.isActive) {
            coroutine.resume(true)
        }
    }
    dialog.show()
    lifecycle.addObserver(object : DefaultLifecycleObserver {
        override fun onResume(owner: LifecycleOwner) {
            owner.launchUI({
                if (coroutine.isActive && checkPay(payModel.orderSn)) {
                    SafeDialogHandle.safeDismissDialog(dialog)
                    coroutine.resume(true)
                }
            })
        }

        override fun onDestroy(owner: LifecycleOwner) {
            SafeDialogHandle.safeDismissDialog(dialog)
        }
    })
}

suspend fun checkPay(orderSn: String?): Boolean = MALL_API_SERVICE.payQuery(orderSn).data?.payStatus == 1